# 3.1导入蓝图对象
import random
import re
from datetime import datetime

from flask import current_app, jsonify
from flask import json
from flask import request, make_response
from flask import session

from info import constants, redis_store, db
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.modules.passport import passport_blue
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET


# 3.2 使用蓝图实现路由
# 在实际开发中，接口的地址和参数是后端人员确定的－可以和前段商量
@passport_blue.route("/logout", methods=['POST'])
def logout():
    """
    清除session中的对应登录之后保存的信息
    """
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)

    # 返回结果
    return jsonify(errno=RET.OK, errmsg="OK")


# 参数：　手机号码/密码
@passport_blue.route('/login', methods=["POST"])
def login():
    # 1.获取参数和判断是否值
    json_dict = request.json
    mobile = json_dict.get('mobile')
    password = json_dict.get('password')

    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
    if not re.match(r'1[3456789]\d{9}', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码错误')
    # 2.从数据库查询指定的用户
    try:
        user = User.query.flter_by(mobile=mobile).filter()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库错误')

    if not user:
        # 用户不存在
        return jsonify(errno=RET.NODATA, errmsg='用户名不存在')
    # 3.校验密码
    if not user.check_passowrd(password):
        return jsonify(errno=RET.PWDERR, errmsg='用户名或密码错误')
    # 为了防止暴力破解，建议放到一起写
    # if not user or user.password_hash != password:

    # 4,保存用户登录状态
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile
    # 设置最后登录时间
    # 修改了模型属性之后，需要提交－>自动提交
    user.last_login = datetime.now()

    # 5,返回成功信息－>
    return jsonify(erron=RET.OK, errmsg='登录成功')


# 注册
# 请求方式：ＰＯＳＴ
# URL：/PASSPORT/SM_CODE?
# 参数：mobile,sms_code ,password


@passport_blue.route('/')
def register():
    # １,获取参数
    json_dict = request, json
    mobile = json_dict.get('moblie')
    sms_code = json_dict.get('sms_code')
    password = json_dict.get('password')
    # 2,参数校验
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')

    if not re.match(r'1[3456789]\d{9}', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号码错误')
    # 3, 逻辑处理,从redis获取短信验证码(判断是否过期)
    try:
        real_sms_code = redis_store.get('sms_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')

    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期　')

    # 4,对比验证码，对比失败返回错误
    if real_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')
    # 删除验证码(对比完，就没用了，虽然过期就自动删除，但是为了保险（安全／逻辑完善）)
    try:
        redis_store.delete('SMS_' + mobile)
    except Exception as e:
        current_app.logger.error(e)

        # 从逻辑严紧性上来说，有错误就返回错误信息，让前端处理
        # 从产品经理角度，不要返回错误信息
        # return jsonify(errno=RET.NODATA, errmsg='数据库查询失败')

        # 5,对比成功，注册用户（１,判断手机号是否注册过，２,创建User模型，３.添加到数据库）
        # 5.1　判断手机号码是否注册
        try:
            user = User.query.flter_by(mobile=mobile).first()

        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')

        if user:
            # 用户已经存在
            return jsonify(errno=RET.DATAEXIST, errmsg='用户已经存在')

            # 5.2, 创建User 模型
        user = User()
        user.nick_name = mobile
        user.mobile = mobile
        # TODO() 密码加密为处理
        # user.password_hash = password
        user.password = password

        # 5.3 添加到数据库
        try:
            db.session.add(user)
            db.session.cmmit()
        except Exception as e:
            # 数据库修改操作，失败要回滚
            db.session.rollback()
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')

            # 6.实现登录--->session
        session['user_id'] = user.id
        session['nick_name'] = user.nick_name
        session['mobile'] = user.mobile

        # 7. 返回成功数据,前段接收到成功信息，刷新界面即可
        return jsonify(errno=RET.OK, errmsg='注册成功')


# 获取短信验证码URL：127.0.0.1:5000/PASSPORT/SM_CODE?
# 参数：mobile,image_code ,image_code_id


@passport_blue.route('/sm_code', methods=['post'])
def get_sm_code():
    # 代码的步骤分析
    # １,获取参数(手机号/图像验证码内容/图像验证码ID)
    # request.data接收的是json的格式的字符串
    # json.load(request.data.get)
    params_dict = request.json
    mobile = params_dict.get('mobile')
    image_code = params_dict.get('image_code')
    image_code_id = params_dict.get('image_code_id')

    # ２,校验数据(数据完全性/正则匹配手机号)
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不全')
    if not re.match('1[3456789][0-9]{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号码格式错误')

    # ３,逻辑处理(先从redis中获取数据(需要判断是否有数据)try)
    try:
        real_image_code = redis_store.get('image_code_id_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据失败')
    # 要判断redis过期情况
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码已过期')
    # 4,用户传入的于服务器的验证码的做对比（如果失败，返回错误信息JSON）
    # ４,1　无论对比成功与否，只要获取到了服务器的验证码，就可以删除
    try:
        redis_store.delete('image_code_id_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='删除数据失败')
    # 4.2 对比
    if real_image_code.upper != image_code.upper:
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')

    # 4.3应该在对比完图像验证码之后，再去查询用户是否存在
    try:
        user = User.query.flter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')

    if user:
        # 用户已经存在
        return jsonify(errno=RET.DATAEXIST, errmsg='用户已经存在')

    # 5,如果对比一致,保存到redis中生成的验证码的值（第三方只负责发送短信）
    # 06d:　以６位返回，如果不足６位，以０补齐
    sms_code_str = '%06d' % random.randint(0, 999999)
    current_app.logger.debug('sms_code: %s' % sms_code_str)
    # 6,调用第三方发送的短信
    result = CCP().send_template_sms(mobile, [sms_code_str, constants.SMS_CODE_REDIS_EXPIRES], 1)
    if result != 0:
        # 表示发送失败
        return jsonify(errno=RET.THIRDERR, errmsg='短信发送失败')
    # 保存到redis中
    try:
        redis_store.set('SMS_' + mobile, sms_code_str, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.OK, errmsg='短信验证码保存redis中失败')
    # 7,返回数据/成功的数据
    return jsonify(errno=RET.OK, errmsg='短信验证码发送成功')


# 获取图像验证码的路由/接口
# ＵＲＬ:/passport/image_code?image_code_id=xxxxx


@passport_blue.route('/image_code')
def get_image_code():
    # 1.获取参数ID
    image_code_id = request.args.get('image_code_id')

    # 2. 生成验证码的内容(名字随便写)
    name, text, image_data = captcha.generate_captcha()

    # 3.保存到redis中去
    try:
        redis_store.set('image_code_id_' + image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        # 记录到日志中
        current_app.logger.error(e)
        # 返回一个错误信息，前后端的数据，都用ＪＳＯＮ来返回，通知前段来返回更新数据
        # {'errno':'4000',errmsg:保存图片验证码失败}
        return make_response(jsonify(errno=RET.DATAERR, errmsg='保存图片验证码失败'))
    # 4.返回图像
    response = make_response(image_data)
    response.headers['Content-Type'] = '/image/jpg'
    return response
